package cn.st4rlight.util.strategy;

import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;

import com.google.common.collect.Maps;

import cn.st4rlight.util.value.SafeUtil;

/**
 * 抽象策略工厂
 * @param <E> 所支持的策略枚举类型
 * @param <R> 目标策略接口，需要继承基础接口
 * @author st4rlight <st4rlight@163.com>
 * Created on 2025-10-13
 */
@SuppressWarnings("unchecked")
public abstract class AbstractStrategyFactory<E extends Enum<E>, R extends IBaseGenericStrategy<E>> {

    // 策略工厂
    private final Map<E, R> allStrategyMap = Maps.newConcurrentMap();


    protected AbstractStrategyFactory(List<R> strategyList) {
        // 初始化map并写入当前的所有策略实现
        for (R currStrategy : strategyList) {
            SafeUtil.of(currStrategy.supportTypes()).forEach(supportType ->
                    this.allStrategyMap.put(supportType, currStrategy));
        }

        // 获取当前的枚举泛型
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class<E> enumClass = (Class<E>) genericSuperclass.getActualTypeArguments()[0];

        // 检查当前是否有未实现的枚举
        Set<E> ignoreTypes = this.supplyIgnoreTypes();
        Set<E> eventTypeSet = this.allStrategyMap.keySet();
        for (E enumValue : enumClass.getEnumConstants()) {
            if (!eventTypeSet.contains(enumValue) && !ignoreTypes.contains(enumValue)) {
                String errMsg = String.format("初始化异常，未找到【%s】的策略实现", enumValue.name());
                throw new IllegalArgumentException(errMsg);
            }
        }
    }

    /**
     * 根据不同的类型获取不同的策略实现
     */
    public R getStrategy(E currType) {
        return this.allStrategyMap.get(currType);
    }

    /**
     * 根据不同的类型获取不同的策略实现（带默认策略）
     */
    public R getStrategy(E currType, R defaultStrategy) {
        return this.allStrategyMap.getOrDefault(currType, defaultStrategy);
    }

    /**
     * 根据不同的类型获取不同的策略实现（带默认策略）
     */
    public R getStrategy(E currType, Supplier<R> defaultSupplier) {
        R result = this.allStrategyMap.get(currType);
        if (Objects.isNull(result)) {
            result = defaultSupplier.get();
        }
        return result;
    }

    /**
     * 当前需要忽略的枚举类型
     * NOTE: 一般用于比如UNKNOWN这种不需要策略实现的场景
     */
    protected Set<E> supplyIgnoreTypes() {
        return Collections.emptySet();
    }
}
